///////////////////
/// mkII - Core ///
///////////////////

#pragma once

namespace mk
{
namespace Core
{
namespace Math
{

MK_FORCEINLINE MK_MATH_VECTOR4_CTOR
(
)
{
}

MK_FORCEINLINE MK_MATH_VECTOR4_CTOR
(
    real32 const x,
    real32 const y,
    real32 const z,
    real32 const w
)
{
    __declspec (align(16)) real32 r[4];
    r[0] = x;
    r[1] = y;
    r[2] = z;
    r[3] = w;
    *this = LoadVector4( r );
}

MK_FORCEINLINE MK_MATH_VECTOR4_CTOR
(
    real32 const v
)
{
    *this = v;
}

MK_FORCEINLINE MK_MATH_VECTOR4_CTOR
(
    Vector128r v
)
{
    r = v;
}

MK_FORCEINLINE MK_MATH_VECTOR4_CTOR
(
    Vector128i v
)
{
    i = v;
}

MK_FORCEINLINE Vector4& operator=
(
    Vector4ConstValue v
)
{
    r = v.r;
    return *this;
}

MK_FORCEINLINE Vector4& operator=
(
    Vector128r v
)
{
    r = v;
    return *this;
}

MK_FORCEINLINE Vector4& operator=
(
    Vector128i v
)
{
    i = v;
    return *this;
}

MK_FORCEINLINE bool operator==
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsEqual(a, b);
}

MK_FORCEINLINE bool operator!=
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return !(a == b);
}

MK_FORCEINLINE bool operator<
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsLess(a, b);
}

MK_FORCEINLINE bool operator<=
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsLessEq(a, b);
}

MK_FORCEINLINE bool operator>
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsGreater(a, b);
}

MK_FORCEINLINE bool operator>=
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsGreaterEq(a, b);
}

MK_FORCEINLINE Vector4 const operator+
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Add(a, b);
}

MK_FORCEINLINE Vector4 const operator-
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Sub(a, b);
}

MK_FORCEINLINE Vector4 const operator*
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Mul(a, b);
}

MK_FORCEINLINE Vector4 const operator/
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return Div(a, b);
}

MK_FORCEINLINE Vector4& operator+=
(
    Vector4&            a,
    Vector4ConstValue   b
)
{
    return a = Add(a, b);
}

MK_FORCEINLINE Vector4& operator-=
(
    Vector4&            a,
    Vector4ConstValue   b
)
{
    return a = Sub(a, b);
}

MK_FORCEINLINE Vector4& operator*=
(
    Vector4&            a,
    Vector4ConstValue   b
)
{
    return a = Mul(a, b);
}

MK_FORCEINLINE Vector4& operator/=
(
    Vector4&            a,
    Vector4ConstValue   b
)
{
    return a = Div(a, b);
}

MK_FORCEINLINE Vector4 operator+
(
    Vector4ConstValue v
)
{
    return v;
}

MK_FORCEINLINE Vector4 operator-
(
    Vector4ConstValue v
)
{
    return XOr( v, Vector4(Constants::uint_sign_mask) );
}

MK_FORCEINLINE Vector4 const LengthSq
(
    Vector4ConstValue v
)
{
    return Mul( v, v );
}

MK_FORCEINLINE Vector4 const SafeReciprocal
(
    Vector4ConstValue v,
    Vector4ConstValue r
)
{
    Vector4 grMask = IsGreaterMask( Abs(v), Vector4(Constants::real4_epsilon) );
    return Select( grMask, Reciprocal(v), r );
}

MK_FORCEINLINE Vector4 const ReciprocalSqrt
(
    Vector4ConstValue v
)
{
    return Reciprocal(Sqrt(v));
}

MK_FORCEINLINE Vector4 const SafeReciprocalSqrt
(
    Vector4ConstValue v,
    Vector4ConstValue r
)
{
    Vector4 vsqrt  = Sqrt(v);
    Vector4 grMask = IsGreaterMask( Abs(vsqrt), Vector4(Constants::real4_epsilon) );
    return Select( grMask, Reciprocal(vsqrt), r );
}

MK_FORCEINLINE Vector4 const Abs
(
    Vector4ConstValue v
)
{
    return And( v, Vector4(Constants::uint_value_mask) );
}


MK_FORCEINLINE Vector4 const Lerp
(
    Vector4ConstValue a,
    Vector4ConstValue b,
    Vector4ConstValue t
)
{
    return MAdd((b - a), t, a);
}

MK_FORCEINLINE Vector4 const Clamp
(
    Vector4ConstValue v,
    Vector4ConstValue min,
    Vector4ConstValue max
)
{
    return Max( Min( v, max ), min );
}

MK_FORCEINLINE Vector4 const IsGreaterMask
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsLessMask( b, a );
}

MK_FORCEINLINE Vector4 const IsGreaterEqMask
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    return IsLessEqMask( b, a );
}

MK_FORCEINLINE bool IsEqual
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector4 mask = IsEqualMask(a, b);
    return IsTrue(mask);
}

MK_FORCEINLINE bool IsLess
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector4 mask = IsLessMask(a, b);
    return IsTrue(mask);
}

MK_FORCEINLINE bool IsLessEq
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector4 mask = IsLessEqMask(a, b);
    return IsTrue(mask);
}

MK_FORCEINLINE bool IsGreater
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector4 mask = IsGreaterMask(a, b);
    return IsTrue(mask);
}

MK_FORCEINLINE bool IsGreaterEq
(
    Vector4ConstValue a,
    Vector4ConstValue b
)
{
    Vector4 mask = IsGreaterEqMask(a, b);
    return IsTrue(mask);
}

MK_FORCEINLINE bool IsFinite
(
    Vector4ConstValue v
)
{
    return IsLessEq( Abs(v), Vector4( MK_REAL32_MAX ) );
}

} // namespace Math
} // namespace Core
} // namespace mk

